package com.bootdo.app.service.impl;

import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bootdo.app.common.aop.exception.BaseException;
import com.bootdo.app.common.aop.exception.ExceptionEnum;
import com.bootdo.app.common.aop.exception.MiniprogramException;
import com.bootdo.app.common.aop.exception.WXException;
import com.bootdo.app.common.utils.BeanUtil;
import com.bootdo.app.common.utils.WXPayUtil;
import com.bootdo.app.config.WXConfig;
import com.bootdo.app.dto.wx.TemplateMsgRequest;
import com.bootdo.app.dto.wx.TransferMoneyRequest;
import com.bootdo.app.vo.wx.TransferMoneyResponse;
import com.bootdo.app.vo.wx.WxAccessTokenResponse;
import com.bootdo.common.config.BootdoConfig;
import com.bootdo.app.service.WXService;
import com.bootdo.app.vo.wx.Code2SessionVo;
import com.bootdo.system.domain.TbWxToken;
import com.bootdo.system.mapper.TbWxTokenMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.net.ssl.SSLSocketFactory;
import java.security.KeyStore;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

/**
 * @auther: Along
 * @description: 微信第三方接口实现
 */
@Slf4j
@Service
public class WXServiceImpl implements WXService {

    @Autowired
    private TbWxTokenMapper wxTokenMapper;
    
    @Autowired
	private BootdoConfig bootdoConfig;


    /**
     * 获取微信AccessToken
     *
     * @param appId     appId
     * @param appSecret appSecret
     * @return
     */
    @Override
    public String getAccessToken(String appId, String appSecret) {

        TbWxToken tbWxToken = wxTokenMapper.selectByAppId(appId);
        // 未过期
        if (tbWxToken != null) {
            Date updateDateTime = tbWxToken.getUpdateDateTime();
            Calendar calendar = Calendar.getInstance();
            Date now = calendar.getTime();
            calendar.setTime(updateDateTime);
            calendar.add(Calendar.HOUR, 1);
            Date expireTime = calendar.getTime();
            if (expireTime.compareTo(now) > 0) {
                return tbWxToken.getAuthAccessToken();
            }
        }
        // 过期
        try {
            String result = HttpUtil.createGet(WXConfig.getAccessTokenUrl(appId, appSecret)).execute().body();
            log.info("获取微信AccessToken---result:{}", result);
            WxAccessTokenResponse wxAccessTokenResponse = JSON.parseObject(result, WxAccessTokenResponse.class);
            if (wxAccessTokenResponse != null && wxAccessTokenResponse.getErrcode() == null ) {
                String access_token = wxAccessTokenResponse.getAccess_token();
                TbWxToken wxToken = new TbWxToken();
                wxToken.setAppId(appId);
                wxToken.setAppSecret(appSecret);
                wxToken.setAuthAccessToken(access_token);
                wxTokenMapper.insertSelective(wxToken);
                return access_token;
            }
            throw new BaseException("获取微信AccessToken失败");
        } catch (HttpException e) {
            log.error("取微信AccessToken异常:", e);
            throw new MiniprogramException(ExceptionEnum.WX_REQUEST_TIME_OUT);
        }
    }

    /**
     * 创建微信公众号菜单
     *
     * @param appId      公众号 appId
     * @param appSecret  公众号 AppSecret
     * @param wxMenuJson 创建的微信菜单 json
     * @return
     */
    @Override
    public boolean createWxMenu(String appId, String appSecret, String wxMenuJson) {
        String accessToken = this.getAccessToken(appId, appSecret);
        String createWxMenuUrl = WXConfig.getCreateWxMenuUrl(accessToken);
        try {
            String result = HttpUtil.createPost(createWxMenuUrl).body(wxMenuJson).execute().body();
            log.info("创建微信菜单---result:{}", result);
            JSONObject jsonObject = JSON.parseObject(result);
            String errcode = jsonObject.getString("errcode");
            if ("0".equals(errcode)) {
                return true;
            }
        } catch (HttpException e) {
            log.error("创建微信菜单请求异常:{}", e);
            throw new MiniprogramException(ExceptionEnum.WX_REQUEST_TIME_OUT);
        }
        return false;
    }

    /**
     * 【微信小程序】- code2SessionDto 接口
     *
     * @param appId     appId
     * @param appSecret appSecret
     * @param code      code
     * @return
     */
    @Override
    public Code2SessionVo code2Session(String appId, String appSecret, String code) {

        final String url = WXConfig.initCode2Session(appId, appSecret, code);
        try {
            String resultJson = HttpUtil.get(url);
            log.info("微信小程序code2Session:请求url = {},响应json = {}", url, resultJson);
            return JSON.parseObject(resultJson, Code2SessionVo.class);
        } catch (HttpException e) {
            log.error("微信小程序code2Session接口请求异常：{}", e);
        }
        throw new WXException(ExceptionEnum.WX_REQUEST_ERROR);
    }

    /**
     * 配置API安全证书 (https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=4_3)
     */
    @Override
    public TransferMoneyResponse transferMoneyToUser(TransferMoneyRequest request) {
        log.info("提现请求参数:{}", request);
        String password = request.getMchid();
        String uploadPath = bootdoConfig.getUploadPath();
//        KeyStore keyStore = WXPayUtil.loadKeyStore("PKCS12", WXConfig.getSslFilePath(), password);
        KeyStore keyStore = WXPayUtil.loadKeyStore("PKCS12",uploadPath+"wxSSLConfig/apiclient_cert.p12", password);
        log.info("获取 SSL 证书密钥 keyStore:{}", keyStore);
        SSLSocketFactory sslFactory = WXPayUtil.getSSLFactory(keyStore, password);
        log.info("获取 SSL 套接字工厂 sslFactory:{}", sslFactory);
        Map map = BeanUtil.beanToMap(request);
        log.info("待签名参数:{}", map);
        map.put("sign", WXPayUtil.md5ContentSign(map, WXPayUtil.SALT, WXPayUtil.SIGN_CHARSET));
        HttpRequest post = HttpUtil.createPost(WXConfig.getTransferMoneyToUserUrl());
        if (sslFactory == null) {
            throw new BaseException("SSL安全证书不存在");
        }
        post.setSSLSocketFactory(sslFactory);
        log.info("设置SSL安全证书成功");
        String xml = WXPayUtil.mapToXml(map);
        log.info("微信付款到零钱请求 xml = {}", xml);
        try {
            String result = post.body(xml).execute().body();
            log.info("微信付款到零钱请求结果 result = {}", result);
            return WXPayUtil.parseWeiXinXml(TransferMoneyResponse.class, result);
        } catch (Exception e) {
            log.error("微信付款到零钱请求异常:{}", e);
        }
        return null;
    }

    /**
     * 发送微信公众号模板消息
     *
     * @param appId       公众号 appId
     * @param appSecret   公众号 appSecret
     * @param templateMsg 公众号消息模板
     */
    @Override
    public void sendTemplateMsg(String appId, String appSecret, TemplateMsgRequest templateMsg) {
    	log.error("发送微信公众号模板消息"+templateMsg.toString());
        try {
            HttpUtil.createPost(WXConfig.getSendTemplateMsgUrl(this.getAccessToken(appId, appSecret)))
                    .body(JSON.toJSONString(templateMsg))
                    .execute()
                    .body();
        } catch (HttpException e) {
            log.error("发送微信公众号模板消息异常:{}", e);
        }
    }

}
